Skip to content

fix(lambda): add console credential fallback for Lambda URI handler#8537

Merged
ashishrp-aws merged 13 commits intoaws:masterfrom
keenwilson:feature/console-to-ide-credentials
Jan 29, 2026
Merged

fix(lambda): add console credential fallback for Lambda URI handler#8537
ashishrp-aws merged 13 commits intoaws:masterfrom
keenwilson:feature/console-to-ide-credentials

Conversation

@keenwilson
Copy link
Contributor

@keenwilson keenwilson commented Jan 27, 2026

Problem

  • Users without pre-configured credentials encounter authentication errors when opening Lambda functions from console
  • Credential mismatches between console account and local profile cause errors even when function is accessible in console:
    • ResourceNotFoundException when function exists in console account but not in local profile account
    • AccessDeniedException when local credentials lack lambda:GetFunction permission but console credentials have access

Solution

  • Add setupConsoleConnection() to encapsulate browser-based AWS CLI aws login authentication and use the new connection
  • Add getFunctionWithFallback() to retrieve Lambda configuration with automatic console login fallback
  • Integrate fallback into openLambdaFolderForEdit() to handle missing credentials and credential mismatches
  • Improve error handling to distinguish credential mismatches and resource access issues
    • Handle ResourceNotFoundException by showing account-specific error message before fallback
    • Handle AccessDeniedException by showing permission error message before fallback

Screenshots

Show warning message when Lambda GetFunction API returns ResourceNotFoundException, then automatically proceed with console login flow

Screenshot 2026-01-29 at 12 29 00 AM

Show warning message when Lambda GetFunction API returns AccessDeniedException, then automatically proceed with console login flow

Screenshot 2026-01-29 at 12 28 07 AM

Background

The Lambda load-function URI handler enables a seamless workflow where users can click "Open in Visual Studio Code" from the AWS Lambda console to view, edit, and deploy their Lambda functions directly in their preferred IDE. This feature downloads the function code locally, opens it in VS Code, and allows users to make changes and deploy updates back to AWS—all without leaving their development environment.

Testing

  • Tested with no local credentials configured
  • Tested credential mismatch scenarios:
    • ResourceNotFoundException (function in console account but not local profile account)
    • AccessDeniedException (local credentials lack permission, console credentials have access)
  • Tested user cancellation flow
  • Test with SSO connection active

  • Treat all work as PUBLIC. Private feature/x branches will not be squash-merged at release time.
  • Your code changes must meet the guidelines in CONTRIBUTING.md.
  • License: I confirm that my contribution is made under the terms of the Apache 2.0 license.

@keenwilson keenwilson requested a review from a team as a code owner January 27, 2026 23:11
@amazon-inspector-ohio
Copy link

⏳ I'm reviewing this pull request for security vulnerabilities and code quality issues. I'll provide an update when I'm done

@amazon-inspector-ohio
Copy link

✅ I finished the code review, and didn't find any security or code quality issues.

@keenwilson keenwilson force-pushed the feature/console-to-ide-credentials branch 2 times, most recently from 3aca6d4 to 7e51e8f Compare January 27, 2026 23:31
@keenwilson keenwilson force-pushed the feature/console-to-ide-credentials branch from 7e51e8f to ea1adf8 Compare January 27, 2026 23:52
export async function getIAMConnectionOrFallbackToConsole(name: string, region: string): Promise<Connection> {
const tryActiveConnection = await getIAMConnection({ prompt: false })

if (tryActiveConnection && isIamConnection(tryActiveConnection)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to check that it's an IamConnection?

The previous getFunctionWithCredentials used a fromSSO for the case where the connection wasn't iam.

const credentials =
connection.type === 'iam' ? await connection.getCredentials() : fromSSO({ profile: connection.id })

should we still consider that case too before going to create a console connection?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. I removed the IamConnection type pre-check.

Comment on lines +243 to +246
const connection = await getIAMConnectionOrFallbackToConsole(name, region)

try {
return await getFunctionWithCredentials(region, name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We retrieved the credentials in this getIAMConnectionOrFallbackToConsole, but then we're not using those credentials here, so inside this method we need to get the credentials again. Shouldn't we pass the credentials directly here, now that we have them? Or is there a reason to just make the method retrieve them directly instead of passing them as a parameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing this out. I removed getIAMConnectionOrFallbackToConsole entirely since it duplicated credential retrieval logic in getFunctionWithCredentials.

getLogger().warn(message)
}
// Retry once with console credentials after credential mismatch. If second attempt fails, throw the error up.
await createAndUseConsoleConnection(name, region)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm the behavior:
So we're trying to get the credentials. If there are credentials we use those, but if they don't exist, we create the console connection.
Then we try to get the function, but if we fail because of different reasons, then we try again to create the console connection.

Could it happen that we create the console connection twice? If they didn't have a connection initially so we create the console connection, but then their console session has one of these errors? (maybe we want to retry?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a very good point. I cleaned up the retry behavior to avoid setting up console connection for the second-time.

Here are the current scenarios handled by getFunctionWithFallback:

Active connection → success (no console setup)
Active connection → get function error (ResourceNotFoundException/AccessDeniedException) → show message → console retry → success
Active connection → get function error (other errors) → console retry (no message) → success
No connection → console setup → success
No connection → console setup → get function error (ResourceNotFoundException/AccessDeniedException) → show message → throw (no retry)
No connection → console setup → get function error (other errors) → throw (no message, no retry)
No connection → console setup error → throw (no message)

* @returns Connection created from console credentials
* @throws ToolkitError if connection creation fails
*/
export async function createAndUseConsoleConnection(profileName: string, region: string): Promise<Connection> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small thing but i wonder since this method says it's doing two things by way of the "and" should it be split into two methods for maintainability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I refactored the credential ID handling and made this function (renamed to setupConsoleConnection) only owns the console-connection setup path. The extra getConnection check was removed since useConnection already validates internally.

await tryActiveConnection.getCredentials()
return tryActiveConnection
} catch (error) {
// Fall back to console credentials for any credential retrieval error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we log something here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we removed the redundant credential pre-check, this log is no longer needed.

* @throws ToolkitError if console login fails
*/
export async function getIAMConnectionOrFallbackToConsole(name: string, region: string): Promise<Connection> {
const tryActiveConnection = await getIAMConnection({ prompt: false })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: lets just name this activeConnection, feels redundant to have "tryActiveConnection" inside the try block

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really appreciate the detailed feedback. I updated to activeConnection. Thanks a lot, Seshu.

@ashishrp-aws ashishrp-aws merged commit 8dccd29 into aws:master Jan 29, 2026
34 checks passed
laileni-aws pushed a commit that referenced this pull request Feb 20, 2026
…r fails (#8580)

## Problem

- #8537 introduced
setupConsoleConnection() and getFunctionWithFallback() to handle
authentication fallback for Lambda console-to-IDE transitions.
- When developers click "Open in VSCode" and their local AWS profile is
invalid, toolkit automatically triggers browser-based console login as a
fallback. However, console login requires prerequisites that not all
developers can complete. When developers cancel console login, the CLI
never writes the connection profile to disk. The Toolkit then attempts
to use this non-existent connection, resulting in "Connection does not
exist" errors.






<img width="471" height="265"
alt="problem-before-the-fix-connection-does-not-exist"
src="https://github.com/user-attachments/assets/fd973ce1-7b28-4474-8b55-b0408c67e0ce"
/>


## Solution

- Verify connection exists in `setupConsoleConnection()` after
"aws.toolkit.auth.consoleLogin" completes
- Show warning message with link to [prerequisites
documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-sign-in.html#cli-configure-sign-in-prerequisites)
when connection verification fails
- Throw ToolkitError to halt execution and prevent downstream connection
usage

<img width="1293" height="302" alt="update-message-with-learnmore"
src="https://github.com/user-attachments/assets/a1d35f14-4c42-43c1-8417-b6532ed00e9a"
/>

<img width="1042" height="625" alt="click-learnmore-show-dialog"
src="https://github.com/user-attachments/assets/aace3330-4ea8-4bd8-ad24-e8e956f09c45"
/>


### Background

The Lambda load-function URI handler enables a seamless workflow where
users can click "Open in Visual Studio Code" from the AWS Lambda console
to view, edit, and deploy their Lambda functions directly in their
preferred IDE. This feature downloads the function code locally, opens
it in VS Code, and allows users to make changes and deploy updates back
to AWS—all without leaving their development environment.



---

- Treat all work as PUBLIC. Private `feature/x` branches will not be
squash-merged at release time.
- Your code changes must meet the guidelines in
[CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines).
- License: I confirm that my contribution is made under the terms of the
Apache 2.0 license.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants